﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Silverlight.Hosting.Private;
using System.Drawing;
using Silverlight.Hosting.Interop;
using System.Runtime.InteropServices.ComTypes;
using System.IO;
using System.ComponentModel;


namespace Silverlight.Hosting
{
    public class SilverlightWindowlessHost : Control, ISilverlightHost
    {
        private XcpWindowlessContainerProxy _container;
        private BufferedGraphicsRenderer _renderer;
        private bool _ignoreDialogKeys;
        private bool _renderingEnabled = true;
        private bool _renderingEnabledCore;

        public SilverlightWindowlessHost()
        {
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.BackColor = Color.Transparent;

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);

            _container = new XcpWindowlessContainerProxy(this);
            _renderer = new BufferedGraphicsRenderer(this);

            IsRenderingEnabledCore = IsRenderingEnabled;
        }

        #region Public Events

        /// <summary>
        /// Raised when the Silverlight control is created.
        /// </summary>
        public new event EventHandler Created;

        /// <summary>
        /// Raised whenever the XAML DOM has successfully loaded (i.e. the application
        /// is fully loaded and ready to display). This notification is useful because
        /// loading Silverlight can take longer for complex applications and when loading
        /// the CLR for the first time. 
        /// </summary>
        public event EventHandler SilverlightLoaded;

        /// <summary>
        /// Raised whenever errors are raised from within the XAML DOM of the hosted control.
        /// This event can indicate when a load failure has occurred, for example, when the
        /// expected .xap file does not exist. You can also use this event to respond to XAML
        /// parsing errors and runtime errors while using the JavaScript API for Silverlight.
        /// </summary>
        public event EventHandler<SilverlightErrorEventArgs> SilverlightError;

        /// <summary>
        /// Raised whenever events occur within the object model of the hosted control.
        /// </summary>
        public event EventHandler<SilverlightEventArgs> SilverlightEvent;

        /// <summary>
        /// Raised when the source download has finished.
        /// </summary>
        public event EventHandler SourceDownloadComplete;

        /// <summary>
        /// Raised when the source download progress changes.
        /// </summary>
        public event EventHandler<SourceDownloadProgressChangedEventArgs> SourceDownloadProgressChanged;

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler MouseClick
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler MouseDoubleClick
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackColorChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BackgroundImageLayoutChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler BindingContextChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ContextMenuChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler CursorChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler EnabledChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler FontChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ForeColorChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler RightToLeftChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler TextChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler Click
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event DragEventHandler DragDrop
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event DragEventHandler DragEnter
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event DragEventHandler DragOver
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler DragLeave
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event GiveFeedbackEventHandler GiveFeedback
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event HelpEventHandler HelpRequested
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event PaintEventHandler Paint
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event QueryContinueDragEventHandler QueryContinueDrag
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event QueryAccessibilityHelpEventHandler QueryAccessibilityHelp
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler DoubleClick
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler ImeModeChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event KeyEventHandler KeyDown
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event KeyPressEventHandler KeyPress
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event KeyEventHandler KeyUp
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event LayoutEventHandler Layout
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event MouseEventHandler MouseDown
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler MouseEnter
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler MouseLeave
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler MouseHover
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event MouseEventHandler MouseMove
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event MouseEventHandler MouseUp
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event MouseEventHandler MouseWheel
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event UICuesEventHandler ChangeUICues
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        new public event EventHandler StyleChanged
        {
            add { throw new NotSupportedException(); }
            remove { }
        }

        #endregion

        #region Protected Properties

        /// <summary>
        /// Gets or sets a value indicating if the Silverlight plug-in should be rendered.
        /// </summary>
        protected virtual bool IsRenderingEnabledCore
        {
            get { return _renderingEnabledCore; }
            set
            {
                if (value && !_renderingEnabledCore)
                {
                    // The on rendered event informs us when a new frame has been rendered
                    // and is ready for presentation
                    _container.FrameRendered += OnSilverlightFrameRendered;
                }
                else if (!value)
                {
                    _container.FrameRendered -= OnSilverlightFrameRendered;
                }

                _renderingEnabledCore = value;
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets or sets a value indicating if the Silverlight plug-in should be rendered.
        /// </summary>
        public bool IsRenderingEnabled
        {
            get { return _renderingEnabled; }
            set
            {
                _renderingEnabled = value;

                if (Parent != null && IsRenderingEnabledCore != value)
                {
                    IsRenderingEnabledCore = value;
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether the control is windowless.
        /// </summary>
        public bool IsWindowless
        {
            get { return true; }
        }

        /// <summary>
        /// Gets a value indicating whether the control has been created.
        /// </summary>
        public bool IsCreated
        {
            get { return _container.IsCreated; }
        }

        /// <summary>
        /// Gets or sets the URL that the hosted control should use as the base for any relative requests made for Source,
        /// to the downloader, etc.
        /// </summary>
        public Uri BaseUrl
        {
            get { return _container.BaseUrl; }
            set { _container.BaseUrl = value; }
        }

        /// <summary>
        /// Gets or sets the XcpHostOptions specified by the host.
        /// </summary>
        public XcpHostOptions HostOptions
        {
            get { return _container.HostOptions; }
            set { _container.HostOptions = value; }
        }

        /// <summary>
        /// Gets or sets the version of the intalled Silverlight plug-in.
        /// </summary>
        public Version Version
        {
            get { return _container.Version; }
            set { _container.Version = value; }
        }

        /// <summary>
        /// Gets or sets the URI specified for the source content (can be a XAML page or a package, depending on
        /// which programming model is used for the Silverlight content).
        /// </summary>
        public Uri Source
        {
            get { return _container.Source; }
            set { _container.Source = value; }
        }

        /// <summary>
        /// Gets or sets the XAML content dispayed in the Silverlight plug-in.
        /// </summary>
        public string Xaml
        {
            get { return _container.Xaml; }
            set { _container.Xaml = value; }
        }

        /// <summary>
        /// Gets a Boolean that declares whether the control's onLoad event has been raised.
        /// </summary>
       public bool IsLoaded
        {
            get { return _container.IsLoaded; }
        }

        /// <summary>
        /// Gets the content sub-object.
        /// </summary>
        public Content Content
        {
            get { return _container.Content; }
        }

        /// <summary>
        /// Gets the settings sub-object.
        /// </summary>
        public Settings Settings
        {
            get { return _container.Settings; }
        }

        /// <summary>
        /// Gets or sets initialization parameters.
        /// </summary>
        public string InitParams
        {
            get { return _container.InitParams; }
            set { _container.InitParams = value; }
        }

        /// <summary>
        /// Gets or sets the URI specified for the splash screen source XAML.
        /// </summary>
        public Uri SplashScreenSource
        {
            get { return _container.SplashScreenSource; }
            set { _container.SplashScreenSource = value; }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Loads the CLR runtime
        /// </summary>
        public void LoadRuntime()
        {
            _container.LoadRuntime();
        }

        /// <summary>
        /// Creates a new instance of a Silverlight helper object.
        /// </summary>
        /// <param name="objectType">Specifies the type of object to create.</param>
        /// <returns>The resulting object.</returns>
        public SafeComObject<IXcpObject> CreateObject(string objectType)
        {
            return _container.CreateObject(objectType);
        }

        /// <summary>
        /// Determines whether the existing Silverlight plug-in
        /// is a matching version or is a compatible version with a specified version string.
        /// </summary>
        /// <param name="version">String specifying the version to check.</param>
        /// <returns>True if the version is supported; otherwise, False.</returns>
        public bool IsVersionSupported(string version)
        {
            return _container.IsVersionSupported(version);
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Called by the hosted control whenever a download is requested. Hosts should implement this method to provide
        /// specialized download behavior for cases where the download might request cross-domain URLs, or where the host
        /// has other restrictions on requests made as a URI.
        /// </summary>
        /// <param name="url">The URL to download.</param>
        /// <param name="callback">The downloader callback implementation.</param>
        /// <param name="stream">The stream containing the downloaded content.</param>
        /// <returns>Returns OK if the download was handled, Pending if it is being done asynchronously, or Default
        /// if Silverlight should handle the download.</returns>
        protected virtual DownloadResult DownloadUrl(string url, IDownloadUrlCallback callback, out Stream stream)
        {
            return _container.InvokeBaseDownloadUrl(url, callback, out stream);
        }

        /// <summary>
        /// Called when the Silverlight control is created.
        /// </summary>
        protected virtual void OnCreated(EventArgs e)
        {
            _container.InvokeBaseOnCreated(e);
            if (Created != null)
            {
                Created(this, e);
            }
        }

        /// <summary>
        /// Called whenever the XAML DOM has successfully loaded.
        /// </summary>
        protected virtual void OnSilverlightLoaded(EventArgs e)
        {
            _container.InvokeBaseOnSilverlightLoaded(e);
            if (SilverlightLoaded != null)
            {
                SilverlightLoaded(this, e);
            }
        }

        /// <summary>
        /// Called whenever errors are raised from within the XAML DOM of the hosted control.
        /// </summary>
        /// <param name="e">The details of the error.</param>
        protected virtual void OnSilverlightError(SilverlightErrorEventArgs e)
        {
            _container.InvokeBaseOnSilverlightError(e);
            if (SilverlightError != null)
            {
                SilverlightError(this, e);
            }
        }

        /// <summary>
        /// Invoked whenever events occur within the object model of the hosted control.
        /// </summary>
        /// <param name="e">The details of the event.</param>
        protected virtual void OnSilverlightEvent(SilverlightEventArgs e)
        {
            _container.InvokeBaseOnSilverlightEvent(e);
            if (SilverlightEvent != null)
            {
                SilverlightEvent(this, e);
            }
        }

        /// <summary>
        /// Called when the source download has finished.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSourceDownloadComplete(EventArgs e)
        {
            _container.InvokeBaseOnSourceDownloadComplete(e);
            if (SourceDownloadComplete != null)
            {
                SourceDownloadComplete(this, e);
            }
        }

        /// <summary>
        /// Called when the source download progress changes.
        /// </summary>
        /// <param name="e">The details of the download progress.</param>
        protected virtual void OnSourceDownloadProgressChanged(SourceDownloadProgressChangedEventArgs e)
        {
            _container.InvokeBaseOnSourceDownloadProgressChanged(e);
            if (SourceDownloadProgressChanged != null)
            {
                SourceDownloadProgressChanged(this, e);
            }
        }

        /// <summary>
        /// Called after the content in the Silverlight plug-in has completely loaded.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnContentLoaded(EventArgs e)
        {
            _container.InvokeBaseOnContentLoaded(e);
        }

        /// <summary>
        /// Called when when the Silverlight plug-in generates a XAML parse error or
        /// run-time error at the native-code level.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnContentError(ErrorEventArgs e)
        {
            _container.InvokeBaseOnContentError(e);
        }

        /// <summary>
        /// Called when the Silverlight plug-in content area receives a host-generated zoom event.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnContentZoomed(EventArgs e)
        {
            _container.InvokeBaseOnContentZoomed(e);
        }

        /// <summary>
        /// Called when the ActualHeight or ActualWidth of the Silverlight plug-in change.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnContentResized(EventArgs e)
        {
            _container.InvokeBaseOnContentResized(e);
        }

        /// <summary>
        /// Called whenever the FullScreen property of the Silverlight plug-in changes.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnFullScreenChanged(EventArgs e)
        {
            _container.InvokeBaseOnFullScreenChanged(e);
        }

        protected override void OnCreateControl()
        {
            base.OnCreateControl();
            _container.CreateControl();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            _container.Size = this.Size;
        }

        protected bool DispatchMessage(ref Message m)
        {
            return _container.DispatchMessage(ref m);
        }

        protected override bool IsInputChar(char charCode)
        {
            return true;
        }

        protected override bool ProcessDialogKey(Keys keyData)
        {
            return _ignoreDialogKeys ? false : base.ProcessDialogKey(keyData); 
        }

        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);

            _container.UIActivate();
        }

        protected override void OnLostFocus(EventArgs e)
        {
            base.OnLostFocus(e);

            _container.UIDeactivate();
        }

        public override bool PreProcessMessage(ref Message msg)
        {
            if (IsUserMode())
            {
                MSG win32Message = MSG.Create(msg.HWnd, msg.Msg, msg.WParam, msg.LParam);

                if (_container._unkControl is IOleInPlaceActiveObject)
                {
                    IOleInPlaceActiveObject activeObj = _container._unkControl as IOleInPlaceActiveObject;

                    int hr = activeObj.TranslateAccelerator(ref win32Message);

                    msg.Msg = win32Message.message;
                    msg.WParam = win32Message.wParam;
                    msg.LParam = win32Message.lParam;
                    msg.HWnd = win32Message.hwnd;

                    if (hr == HRESULT.S_OK)
                    {
                        return true;
                    }
                    else if (hr == HRESULT.S_FALSE)
                    {
                        bool ret = false;

                        _ignoreDialogKeys = true;
                        try
                        {
                            ret = base.PreProcessMessage(ref msg);
                        }
                        finally
                        {
                            _ignoreDialogKeys = false;
                        }
                        return ret;
                    }
                    else
                    {
                        return false;
                    }
                }
            }

            return false;
        }

        protected bool ProcessInput(ref Message m)
        {
            bool processed = true;

            switch ((uint)m.Msg)
            {
                case (int)WindowMessages.WM_KEYDOWN:
                case (int)WindowMessages.WM_LBUTTONDOWN:
                case (int)WindowMessages.WM_MBUTTONDOWN:
                case (int)WindowMessages.WM_RBUTTONDOWN:
                    if (IsUserMode())
                    {
                        Focus();
                    }
                    break;
            }

            uint handled;
            IntPtr zeroPtr = IntPtr.Zero;
            int hr = _container.ProcessInput((uint)m.Msg, (uint)m.WParam, (uint)m.LParam, ref zeroPtr, 0, 0, out handled);

            if (hr < 0 || handled == 0)
            {
                processed = false;
            }

            return processed;
        }

        protected override void WndProc(ref Message m)
        {
            //(Parent as Form).Text = Focused ? "Focused" : "NOT Focused";

            //if (m.Msg != (int)WindowMessages.WM_GETTEXTLENGTH &&
            //    m.Msg != (int)WindowMessages.WM_PAINT &&
            //    m.Msg != (int)WindowMessages.WM_ERASEBKGND &&
            //    m.Msg != (int)WindowMessages.WM_GETTEXT)
            //{
            //    System.Diagnostics.Trace.WriteLine(string.Format("msg:{0} wparam:{1} lparam:{2} hwnd:{3}",
            //        (WindowMessages)m.Msg, m.WParam.ToString("X8"), m.LParam.ToString("X8"), m.HWnd));
            //}

            if (IsRenderingEnabledCore)
            {
                if (ProcessInput(ref m))
                {
                    return;
                }

                switch (m.Msg)
                {
                    // Things we explicitly ignore and pass to the ocx's windproc
                    case (int)WindowMessages.WM_ERASEBKGND:

                    case (int)WindowMessages.WM_REFLECT + (int)WindowMessages.WM_NOTIFYFORMAT:

                    case (int)WindowMessages.WM_SETCURSOR:
                    case (int)WindowMessages.WM_SYSCOLORCHANGE:

                    // Some of the MSComCtl controls respond to this message 
                    // to do some custom painting. So, we should just pass this message
                    // through.
                    //
                    case (int)WindowMessages.WM_DRAWITEM:

                    case (int)WindowMessages.WM_LBUTTONDBLCLK:
                    case (int)WindowMessages.WM_LBUTTONUP:
                    case (int)WindowMessages.WM_MBUTTONDBLCLK:
                    case (int)WindowMessages.WM_MBUTTONUP:
                    case (int)WindowMessages.WM_RBUTTONDBLCLK:
                    case (int)WindowMessages.WM_RBUTTONUP:
                    case (int)WindowMessages.WM_MOUSEMOVE:

                    case (int)WindowMessages.WM_KEYUP:
                    case (int)WindowMessages.WM_SYSKEYUP:
                    case (int)WindowMessages.WM_SYSKEYDOWN:

                    case (int)WindowMessages.WM_CHAR:
                    case (int)WindowMessages.WM_DEADCHAR:
                    case (int)WindowMessages.WM_SYSCHAR:
                    case (int)WindowMessages.WM_SYSDEADCHAR:

                    case (int)WindowMessages.WM_ACTIVATE:

                    case (int)WindowMessages.WM_HELP:

                    case (int)WindowMessages.WM_CONTEXTMENU:

                        if (!DispatchMessage(ref m))
                        {
                            base.WndProc(ref m);
                        }
                        break;

                    case (int)WindowMessages.WM_MOUSEWHEEL:
                    case (int)WindowMessages.WM_MOUSEHWHEEL:
                        {
                            Message copy = Message.Create(m.HWnd, m.Msg, m.WParam, m.LParam);

                            var p = this.PointToClient(new Point(GetXLParam(copy.LParam), GetYLParam(copy.LParam)));
                            copy.LParam = MakeLParam(p.X, p.Y);

                            if (!DispatchMessage(ref copy))
                            {
                                base.WndProc(ref m);
                            }
                        }
                        break;

                    case (int)WindowMessages.WM_KEYDOWN:
                    case (int)WindowMessages.WM_LBUTTONDOWN:
                    case (int)WindowMessages.WM_MBUTTONDOWN:
                    case (int)WindowMessages.WM_RBUTTONDOWN:

                        if (IsUserMode())
                        {
                            Focus();
                        }
                        if (!DispatchMessage(ref m))
                        {
                            base.WndProc(ref m);
                        }
                        break;

                    case (int)WindowMessages.WM_COMMAND:
                        if (!ReflectMessage(/*m.LParam*/_container.Handle, ref m))
                        {
                            if (!DispatchMessage(ref m))
                            {
                                base.WndProc(ref m);
                            }
                        }
                        break;

                    default:
                        base.WndProc(ref m);
                        break;

                }
            }
            else
            {
                base.WndProc(ref m);
            }
        }

        protected override void OnParentChanged(EventArgs e)
        {
            base.OnParentChanged(e);

            IsRenderingEnabledCore = (Parent != null && IsRenderingEnabled);
        }

        protected override void Dispose(bool disposing)
        {
            ReleaseResources();

            base.Dispose(disposing);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x02000000;       //WS_EX_TRANSPARENT
                return cp;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (_renderer.BufferedGraphics != null)
            {
                PaintEventArgs x = new PaintEventArgs(_renderer.BufferedGraphics.Graphics, e.ClipRectangle);
                _renderer.BufferedGraphics.Render(e.Graphics);
            }
            e.Dispose();
        }

        #endregion

        #region Private Methods

        private void ReleaseResources()
        {
            if (_container != null)
            {
                IsRenderingEnabledCore = false;
                _container.Dispose();
                _container = null;
            }

            if (_renderer != null)
            {
                _renderer.Dispose();
                _renderer = null;
            }
        }

        private void OnSilverlightFrameRendered(object sender, FrameRenderedEventArgs e)
        {
            _renderer.RenderFrame(e, base.OnPaintBackground);
            this.Invalidate(e.DirtyRect);
            this.Update();
        }

        private bool IsUserMode()
        {
            System.ComponentModel.ISite site = Site;
            return site == null || !site.DesignMode;
        }

        private static IntPtr MakeLParam(int wLow, int wHigh)
        {
            return (IntPtr)(((short)wHigh << 16) | (wLow & 0xffff));
        }

        private static int GetXLParam(IntPtr lParam)
        {
            return ((int)lParam & 0xffff);
        }

        private static int GetYLParam(IntPtr lParam)
        {
            return ((int)lParam >> 16);
        }

        #endregion

        #region ISilverlightHostEventProvider

        void ISilverlightHostEventProvider.OnCreated(EventArgs e)
        {
            OnCreated(e);
        }
        
        void ISilverlightHostEventProvider.OnSilverlightLoaded(EventArgs e)
        {
            OnSilverlightLoaded(e);
        }

        void ISilverlightHostEventProvider.OnSilverlightError(SilverlightErrorEventArgs e)
        {
            OnSilverlightError(e);
        }

        void ISilverlightHostEventProvider.OnSilverlightEvent(SilverlightEventArgs e)
        {
            OnSilverlightEvent(e);
        }

        void ISilverlightHostEventProvider.OnSourceDownloadComplete(EventArgs e)
        {
            OnSourceDownloadComplete(e);
        }

        void ISilverlightHostEventProvider.OnSourceDownloadProgressChanged(SourceDownloadProgressChangedEventArgs e)
        {
            OnSourceDownloadProgressChanged(e);
        }

        void ISilverlightHostEventProvider.OnContentLoaded(EventArgs e)
        {
            OnContentLoaded(e);
        }

        void ISilverlightHostEventProvider.OnContentError(ErrorEventArgs e)
        {
            OnContentError(e);
        }

        void ISilverlightHostEventProvider.OnContentZoomed(EventArgs e)
        {
            OnContentZoomed(e);
        }

        void ISilverlightHostEventProvider.OnContentResized(EventArgs e)
        {
            OnContentResized(e);
        }

        void ISilverlightHostEventProvider.OnFullScreenChanged(EventArgs e)
        {
            OnFullScreenChanged(e);
        }

        DownloadResult ISilverlightHostEventProvider.DownloadUrl(string url, IDownloadUrlCallback callback, out Stream stream)
        {
            return DownloadUrl(url, callback, out stream);
        }

        #endregion
    }
}
